package scope;

import domain.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.*;
import org.springframework.web.context.annotation.RequestScope;

import java.util.Map;

/**
 * Spring 容器没有办法管理 prototype bean 的完整生命周期，也每办法记录实例是否存在
 * 销毁回调方法将不会执行，可以利用 BeanPostProcessor 进行清理
 * @author jackcfan
 * @date 2021/9/25
 */
@Configuration
public class BeanScopeTest {
    // 默认就是单例 Bean
    @Bean
    @Primary
    public User singletonUser(){
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    // 原型 Bean
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @RequestScope
    public User prototypeUser(){
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    // 注入单例 Bean
    @Autowired
    @Qualifier("singletonUser")
    User singletonUser;

    @Autowired
    @Qualifier("singletonUser")
    User singletonUser1;

    // 注入原型 Bean
    @Autowired
    @Qualifier("prototypeUser")
    User prototypeUser;

    @Autowired
    @Qualifier("prototypeUser")
    User prototypeUser1;

    // 注入集合，Singleton 和 Prototype 均只注入一份对象
    // 即使是 Prototype 对象，也与其他 Prototype 对象不同
    @Autowired
    Map<String, User> users;

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanScopeTest.class);

        // 添加一个 BeanFactoryPostProcessor
        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    System.out.printf("%s Bean 名称:%s 在初始化后回调\n", bean.getClass(), beanName);
                    return bean;
                }
            });
        });

        applicationContext.refresh();

        BeanScopeTest bean = applicationContext.getBean(BeanScopeTest.class);
        System.out.println("------------依赖注入---------------");
        System.out.println("singletonUser == singletonUser1 ? "+(bean.singletonUser == bean.singletonUser1));
        System.out.println("prototypeUser != prototypeUser1 ? "+(bean.prototypeUser != bean.prototypeUser1));

        System.out.println("------------依赖查找---------------");
        User singletonUser = applicationContext.getBean("singletonUser", User.class);
        User singletonUser1 = applicationContext.getBean("singletonUser", User.class);
        User prototypeUser = applicationContext.getBean("prototypeUser", User.class);
        User prototypeUser1 = applicationContext.getBean("prototypeUser", User.class);
        System.out.println("singletonUser == singletonUser1 ? "+(singletonUser == singletonUser1));
        System.out.println("prototypeUser != prototypeUser1 ? "+(prototypeUser != prototypeUser1));

        System.out.println("------------注入集合---------------");
        for(String k : bean.users.keySet()){
            System.out.println(k+"="+bean.users.get(k));
        }
        applicationContext.close();
    }

}
